package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.UploadFileUtil;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

	@Autowired
	private TrackInfoMapper trackInfoMapper;

	@Autowired
	private AlbumInfoMapper albumInfoMapper;

	@Autowired
	private TrackStatMapper trackStatMapper;

	@Autowired
	private VodConstantProperties vodConstantProperties;

	@Autowired
	private VodService vodService;

	@Autowired
	private UserInfoFeignClient userInfoFeignClient;

	@Override
	public Map<String, Object> uploadTrack(MultipartFile file) {
		//初始化客户端对象
		VodUploadClient client = new VodUploadClient(vodConstantProperties.getSecretId(), vodConstantProperties.getSecretKey());
		//构建上传请求
		VodUploadRequest request = new VodUploadRequest();
		//设置本地上传路径
		String tempPath = UploadFileUtil.uploadTempPath(vodConstantProperties.getTempPath(),file);
		request.setMediaFilePath(tempPath);
		//调用上传路径请求
		try {
			VodUploadResponse response = client.upload(vodConstantProperties.getRegion(), request);
			log.info("Upload FileId = {}", response.getFileId());
			//创建一个map对象
			Map<String,Object> map = new HashMap<>();
			map.put("mediaFileId", response.getFileId());
			map.put("mediaUrl", response.getMediaUrl());
			//返回数据
			return map;
		} catch (Exception e) {
			// 业务方进行异常处理
			log.error("Upload Err", e);
		}
		return null;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)//(事务)
	public void saveTrackInfo(TrackInfoVo trackInfoVo, Long userId) {
		//需要的表track_info  track_stat  album_info
		TrackInfo trackInfo = new TrackInfo();
		//属性拷贝
		BeanUtils.copyProperties(trackInfoVo,trackInfo);
		//user_id
		trackInfo.setUserId(userId);
		//order_num 第一种：查询声音表中同一张专辑的最大order_num；第二种：默认值，专辑包含声音总数include_track_count +1
		int orderNum = 0;
		// 查询专辑表中声音总数 1.查询专辑对象
		AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
		if (null != albumInfo){
			orderNum = albumInfo.getIncludeTrackCount() + 1;
		}
		trackInfo.setOrderNum(orderNum);
		//media_duration  media_size  media_type 等数据为空
		//调用云点播的api来获取流媒体数据！
		TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
		//赋值流媒体的数据
		trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
		trackInfo.setMediaType(trackMediaInfoVo.getType());
		trackInfo.setMediaSize(trackMediaInfoVo.getSize());
		trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
		trackInfoMapper.insert(trackInfo);
		//track_stat  声音的统计信息
		this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY);
		this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT);
		this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PRAISE);
		this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT);
		//album_info 专辑信息
		albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
		this.albumInfoMapper.updateById(albumInfo);
	}

	@Transactional(rollbackFor = Exception.class)
	private void saveTrackStat(Long trackId, String statType) {
		//创建对象
		TrackStat trackStat = new TrackStat();
		trackStat.setTrackId(trackId);
		trackStat.setStatType(statType);
		trackStat.setStatNum(new Random().nextInt(100));
		trackStatMapper.insert(trackStat);
	}

	@Override
	public IPage<TrackListVo> findUserTrackPage(Page<TrackListVo> voPage, TrackInfoQuery trackInfoQuery) {
		//  需要查询声音与声音统计信息，此时需要多表关联查询.
		return trackInfoMapper.selectUserTrackPage(voPage,trackInfoQuery);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void removeTrackInfoById(Long trackId) {

		//  album_info中的包含声音总数要-1;
		//  已知只有一个声音Id，需要获取到专辑对象！
		TrackInfo trackInfo = this.getById(trackId);
		//  根据专辑Id获取到专辑对象
		AlbumInfo albumInfo = this.albumInfoMapper.selectById(trackInfo.getAlbumId());
		//  判断
		if (null != albumInfo) {
			//  总数要减一;
			albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount()-1);
		}
		//  添加一行代码！
		albumInfoMapper.updateById(albumInfo);
		//  执行逻辑删除：track_info; track_stat; album_info.include_track_count-1;
		trackInfoMapper.deleteById(trackId);
		//  track_stat
		trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId,trackId));
		//  删除云点播中的数据：
		vodService.removeMedia(trackInfo.getMediaFileId());

		//  track_info; 1 2 3;  1001;  1001 total=3;  2条声音删除了;  track_info 1 3->2;
		//  update track_info set order_num = order_num - 1 where album_id = albumId and is_deleted = 0 and order_num > order_num;
		trackInfoMapper.updateOrderNum(trackInfo.getAlbumId(),trackInfo.getOrderNum());
	}

	@Override
	public void updateTrackInfoById(Long trackId, TrackInfoVo trackInfoVo) {
		//  track_info;
		TrackInfo trackInfo = this.getById(trackId);
		//  可能修改声音！ 你怎么知道用户是否修改了声音? 原有数据库的文件Id
		String originMediaFileId = trackInfo.getMediaFileId();
		//  获取前端页面传递的文件Id
		String mediaFileId = trackInfoVo.getMediaFileId();
		//  赋值：
		BeanUtils.copyProperties(trackInfoVo, trackInfo);
		//  原有的与现在的比较
		if (!originMediaFileId.equals(mediaFileId)){
			//  如果不相等，则说明修改了声音！
			TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(mediaFileId);
			trackInfo.setMediaSize(trackMediaInfoVo.getSize());
			trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
			trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
			trackInfo.setMediaType(trackMediaInfoVo.getType());
			//  删除vod中的声音;
			vodService.removeMedia(originMediaFileId);
		}
		//  赋值声音Id
		trackInfo.setId(trackId);
		//  更新数据
		trackInfoMapper.updateById(trackInfo);
		//  track_stat 删除可选
	}

	@Override
	public IPage<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> albumTrackListVoPage, Long albumId, Long userId) {
		//1.根据专辑Id 和 分页条件 查询声音列表  (能知道当前这张专辑查第一页的数据)
		IPage<AlbumTrackListVo> albumTrackListIPage = trackInfoMapper.selectAlbumTrackPage(albumTrackListVoPage, albumId);
		//获取专辑对象
		AlbumInfo albumInfo = this.albumInfoMapper.selectById(albumId);
		//判断用户的Id是否为空
		if (null == userId){
			//判断专辑类型 免费 付费 vip免费(先获取专辑的类型)
			if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfo.getPayType())){
				// 不是免费专辑 需要将isShowPaidMark这个属性设计为true;
				// 除试听声音之外的都需要设置为付费
				//获取到专辑对应的免费试听集数
				Integer tracksForFree = albumInfo.getTracksForFree();
				//order_num > tracksForFree 就是需要付费的声音  (先拿当当前集合记录)
				albumTrackListIPage.getRecords().stream().filter(track-> track.getOrderNum() > tracksForFree).forEach(track -> track.setIsShowPaidMark(true));
			}
		}else {
			//声明一个变量来标识是否需要付费
			boolean isPaid = false;
			//用户登录
			if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(albumInfo.getPayType())){
				//0102 vip免费
				//用户不是vip 或是vip 但是已经过期了  这都需要付费
				Result<UserInfoVo> userInfoVoResult = this.userInfoFeignClient.getUserInfoVo(userId);
				Assert.notNull(userInfoVoResult.getData(),"用户信息为空");
				UserInfoVo userInfoVo = userInfoVoResult.getData();
				if (userInfoVo.getIsVip()==0 || (userInfoVo.getIsVip()==1 && userInfoVo.getVipExpireTime().before(new Date()))){
					//需要付费
					isPaid = true;
				}
			} else if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(albumInfo.getPayType())) {
				//付费
				isPaid = true;
			}
			// 统一处理付费的情况
			if (isPaid){
				// 获取到需要付费的声音列表， 除去试听声音
				List<AlbumTrackListVo> albumTrackNeedPaidListVoList  = albumTrackListIPage.getRecords().stream().filter(track -> track.getOrderNum() > albumInfo.getTracksForFree()).collect(Collectors.toList());
				//获取到需要付费的声音Id列表
				List<Long> trackIdList = albumTrackNeedPaidListVoList.stream().map(track -> track.getTrackId()).collect(Collectors.toList());
				//需要远程调用判断这个用户是否购买过声音Id 或 专辑， 购买声音需要设置map的key=trackId value=1， 购买过 否则value=0 没有购买过
				Result<Map<Long,Integer>> mapResult = this.userInfoFeignClient.userIsPaidTrack(albumId,trackIdList);
				Assert.notNull(mapResult,"远程调用失败");
				Map<Long, Integer> map = mapResult.getData();
				Assert.notNull(map,"远程调用失败");
				//循环遍历
				albumTrackNeedPaidListVoList.forEach(albumTrackListVo -> {
					/*if (map.get(albumTrackListVo.getTrackId()) == 0){
						albumTrackListVo.setIsShowPaidMark(true);
					}else {
						albumTrackListVo.setIsShowPaidMark(false);
					}*/
					//将上面的代码改为三元表达式
					albumTrackListVo.setIsShowPaidMark(map.get(albumTrackListVo.getTrackId()) == 0 ? true : false);
				});
			}
		}
		return albumTrackListIPage;
	}

	@Override
	public void trackStatUpdate(TrackStatMqVo trackStatMqVo) {
		// 本质就是执行更新操作.
		//  update track_stat set stat_num = stat_num + 1 where track_id = 1 and stat_type = '0701';
		trackInfoMapper.updateTrackStatNum(trackStatMqVo.getTrackId(),trackStatMqVo.getCount(),trackStatMqVo.getStatType());
		if (trackStatMqVo.getStatType().equals(SystemConstant.TRACK_STAT_PLAY)){
			//  更新专辑:
			//  update album_stat set stat_num = stat_num + 1 where album_id = 1 and stat_type = '0401';
			albumInfoMapper.updateAlbumStatNum(trackStatMqVo.getAlbumId(),trackStatMqVo.getCount(),SystemConstant.ALBUM_STAT_PLAY);
		}
	}

	@Override
	public List<Map<String, Object>> findUserTrackPaidList(Long trackId, Long userId) {
		//  根据声音Id获取到当前专辑对应的声音列表;
		TrackInfo trackInfo = this.getById(trackId);
		//  获取声音列表： 所有列表：6-25
		LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId()).gt(TrackInfo::getOrderNum, trackInfo.getOrderNum()).select(TrackInfo::getId);
		List<Long> trackIdList = trackInfoMapper.selectList(wrapper).stream().map(TrackInfo::getId).collect(Collectors.toList());

		//  获取用户已购买的声音集合列表! 已购买：9,10,11
		Result<List<Long>> trackIdListResult = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
		Assert.notNull(trackIdListResult, "用户购买声音列表为空！");
		List<Long> trackIdPaidList = trackIdListResult.getData();
		Assert.notNull(trackIdPaidList, "用户购买声音Id列表为空！");
		//  两个集合要去重获取差集：
		List<Long> trackIdAllPaidList = trackIdList.stream().filter(tId -> !trackIdPaidList.contains(tId)).collect(Collectors.toList());
		//  获取专辑对象
		AlbumInfo albumInfo = this.albumInfoMapper.selectById(trackInfo.getAlbumId());
		//  构建 map 集合了.
        /*
            Map<String, Object> map = new HashMap<>();
            map.put("name","本集"); // 显示文本
            map.put("price",albumInfo.getPrice()); // 专辑声音对应的价格
            map.put("trackCount",0); // 记录购买集数
            list.add(map);
         */
		//  声明一个集合来存储map集合
		List<Map<String,Object>> list = new ArrayList<>();
		if (trackIdAllPaidList.size() > 0) {
			//  声明一个 map 集合.
			Map<String, Object> map = new HashMap<>();
			map.put("name","本集"); // 显示文本
			map.put("price",albumInfo.getPrice()); // 专辑声音对应的价格
			map.put("trackCount",0); // 记录购买集数
			list.add(map);
		}
		//  判断 后10集
		if (trackIdAllPaidList.size() > 10){
			Map<String, Object> map = new HashMap<>();
			map.put("name","后10集"); // 显示文本
			map.put("price",albumInfo.getPrice().multiply(new BigDecimal("10"))); // 专辑声音对应的价格
			map.put("trackCount",10); // 记录购买集数
			list.add(map);
		}
		if (trackIdAllPaidList.size() > 0 && trackIdAllPaidList.size() <= 10){
			Map<String, Object> map = new HashMap<>();
			map.put("name","后"+trackIdAllPaidList.size()+"集"); // 显示文本
			map.put("price",albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(trackIdAllPaidList.size())))); // 专辑声音对应的价格
			map.put("trackCount",trackIdAllPaidList.size()); // 记录购买集数
			list.add(map);
		}
		//  判断 后20集
		if (trackIdAllPaidList.size() > 20){
			Map<String, Object> map = new HashMap<>();
			map.put("name","后20集"); // 显示文本
			map.put("price",albumInfo.getPrice().multiply(new BigDecimal("20"))); // 专辑声音对应的价格
			map.put("trackCount",20); // 记录购买集数
			list.add(map);
		}
		if (trackIdAllPaidList.size() > 10 && trackIdAllPaidList.size() <= 20){
			Map<String, Object> map = new HashMap<>();
			map.put("name","后"+trackIdAllPaidList.size()+"集"); // 显示文本
			map.put("price",albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(trackIdAllPaidList.size())))); // 专辑声音对应的价格
			map.put("trackCount",trackIdAllPaidList.size()); // 记录购买集数
			list.add(map);
		}
		//  判断 后20集
		if (trackIdAllPaidList.size() > 30){
			Map<String, Object> map = new HashMap<>();
			map.put("name","后30集"); // 显示文本
			map.put("price",albumInfo.getPrice().multiply(new BigDecimal("30"))); // 专辑声音对应的价格
			map.put("trackCount",30); // 记录购买集数
			list.add(map);
		}
		if (trackIdAllPaidList.size() > 20 && trackIdAllPaidList.size() <= 30){
			Map<String, Object> map = new HashMap<>();
			map.put("name","后"+trackIdAllPaidList.size()+"集"); // 显示文本
			map.put("price",albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(trackIdAllPaidList.size())))); // 专辑声音对应的价格
			map.put("trackCount",trackIdAllPaidList.size()); // 记录购买集数
			list.add(map);
		}
		//  最多买50集
		if (trackIdAllPaidList.size() > 50){
			Map<String, Object> map = new HashMap<>();
			map.put("name","后50集"); // 显示文本
			map.put("price",albumInfo.getPrice().multiply(new BigDecimal("50"))); // 专辑声音对应的价格
			map.put("trackCount",50); // 记录购买集数
			list.add(map);
		}
		//  返回集合
		return list;
	}

	@Override
	public List<TrackInfo> findPaidTrackInfoList(Long trackId, Integer trackCount) {
		//声明一个集合
		List<TrackInfo> trackInfoList = new ArrayList<>();
		//trackCount大于0或等于0， 等于0的时候，就是购买本集
		//获取当前声音对象
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		//远程调用已购买的声音列表集合
		Result<List<Long>> userPaidTrackListResult = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
		Assert.notNull(userPaidTrackListResult, "用户购买声音列表为空！");
		List<Long> trackIdPaidList = userPaidTrackListResult.getData();
		//Assert.notNull( trackIdList, "用户购买声音Id列表为空！"); 允许为空。
		if (trackCount > 0){
			//需要除去已购买的集数
			//select * from track_info track where order_num >6 and album_if = 1426 limit 10
			LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
			wrapper.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId()).gt(TrackInfo::getOrderNum, trackInfo.getOrderNum());
			//除去已购买的声音集合列表
			if (!CollectionUtils.isEmpty(trackIdPaidList)){
				//  select * from track_info track where order_num > 6 and album_id = 1429 and id not in (48243, 48244) limit 10;
				wrapper.notIn(TrackInfo::getId, trackIdPaidList);
			}
			//拼接limit
			wrapper.last("limit "+trackCount);
			trackInfoList = trackInfoMapper.selectList(wrapper);
		}else {
			//说明购买的本集
			trackInfoList.add(trackInfo);
		}
		return trackInfoList;
	}
}
